package mastermind.view;

import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.GridLayout;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.lang.reflect.Field;
import java.util.HashMap;
import java.util.Map;

import javax.swing.JButton;
import javax.swing.JPanel;

import mastermind.game.Pieces;
import mastermind.net.Protocol;
/**
 * Displays the pegs & pieces state for a MM game
 */
public class MMBoard extends JPanel {
	private static final long serialVersionUID = 3300230073934910744L;
	private PieceButton[][] pieces;
	private JButton[][] pegs;
	private int currentRow;
	private Map<Character, String> colorMap;

	/** 
	 * Construct a new board with given rows and pieces on each row 
	 */
	public MMBoard(int rows, int piecesPerRow) {
		currentRow = 0;

		JPanel pegBoard = new JPanel();
		JPanel pieceBoard = new JPanel();
		pieces = new PieceButton[rows][piecesPerRow];
		pegs = new JButton[rows][piecesPerRow];
		pieceBoard.setLayout(new GridLayout(rows, piecesPerRow));
		pegBoard.setLayout(new GridLayout(rows, piecesPerRow));

		for (int i = 0; i < rows; i++) {
			for (int j = 0; j < piecesPerRow; j++) {
				pieces[i][j] = new PieceButton(i);
				pieceBoard.add(pieces[i][j]);

				pegs[i][j] = new JButton();
				pegBoard.add(pegs[i][j]);
			}
		}
		
		colorMap = new HashMap<Character, String>();
		for(String c : Protocol.pieceColours) {
			colorMap.put(c.charAt(0), c);
		}
		
		setLayout(new BorderLayout());
		add(pegBoard, BorderLayout.WEST);
		add(pieceBoard, BorderLayout.CENTER);
	}

	public void restoreBoard(Map<Pieces, String> guesses) {
		System.out.println("doing restore");
		for(Pieces p : guesses.keySet()) {
			System.out.println("g: " + p);
			for(int i = 0; i < p.getLength(); i++) {
				pieces[currentRow][i].setState(colorMap.get(p.getPiece(i)));
			}
			setPegs(guesses.get(p));
			nextRow();
		}
	}
		
	/**
	 * Return which pieces are selected on the current row
	 */
	public Pieces getSelectedPieces() {
		char[] p = new char[pieces[currentRow].length];
		for (int i = 0; i < pieces[currentRow].length; i++) {
			p[i] = pieces[currentRow][i].getText().toLowerCase().charAt(0);
		}
		return new Pieces(p);
	}
	
	/**
	 * Set current row peg values
	 * 
	 * @param feedback
	 *            String of b/w characters
	 */
	public void setPegs(String feedback) {
		int i = 0;
		for (char c : feedback.toUpperCase().toCharArray()) {
			pegs[currentRow][i].setText(String.valueOf(c));
			i++;
		}
	}

	/**
	 * @return The current row being played
	 */
	public int getRow() {
		return currentRow;
	}

	/**
	 * Moves to next playable row, if one exists, and locks prior rows
	 * 
	 * @return the new current row
	 */
	public int nextRow() {
		if (currentRow+1 < pieces.length) {
			for (int i = 0; i < pieces[currentRow].length; i++) {
				pieces[currentRow][i].setEnabled(false);
				pieces[currentRow + 1][i].setForeground(Color.GRAY);
				if (currentRow + 1 < pieces.length) {
					pieces[currentRow + 1][i].setEnabled(true);
					pieces[currentRow + 1][i].setForeground(Color.BLACK);
				}
			}
			currentRow++;
		}
		return currentRow;
	}

	/** Resets the board states to an initial game */
	public void reset() {
		currentRow = 0;
		for (int i = 0; i < pieces.length; i++) {
			for (int j = 0; j < pieces[j].length; j++) {
				pieces[i][j].setState(Protocol.pieceColours[0]);
				pegs[i][j].setText("");
			}
		}
	}
	
	/** A button that cycles through piece colours when pressed */
	class PieceButton extends JButton {
		private static final long serialVersionUID = 2703153273168105684L;
		private int colorIndex, row;

		/**
		 * Creates a new PieceButton on a given row
		 * 
		 * @param row
		 *            Row this button is on
		 */
		public PieceButton(int row) {
			this.row = row;
			colorIndex = 0;
			setState(Protocol.pieceColours[colorIndex]);
			addActionListener(new ActionListener() {
				public void actionPerformed(ActionEvent arg0) {
					// should only be able to select pieces in the current row
					if (PieceButton.this.row == currentRow) {
						colorIndex = (colorIndex + 1)
								% Protocol.pieceColours.length;
						setState(Protocol.pieceColours[colorIndex]);
					}
				}
			});
		}

		/**
		 * Set button state to a given colour by colour name
		 * 
		 * @param colour
		 *            Name of the colour to set to, ie. "white"
		 */
		private void setState(String colour) {
			// use first char of colour name as label
			setText(String.valueOf(colour.charAt(0)).toUpperCase());

			// grey out if not current row
			setEnabled((row == currentRow));
			setForeground((row != currentRow) ? Color.GRAY : Color.BLACK);

			try {
				// convert colour name into Color object
				Field field = Color.class.getField(colour);
				setBackground((Color) field.get(null));
			} catch (Exception e) {
				// couldn't get a colour, use default
			}
		}
	}

}
